{
    "cells": [
        {
            "cell_type": "code",
            "execution_count": null,
            "metadata": {},
            "outputs": [],
            "source": [
                "import numpy as np\n",
                "import matplotlib\n",
                "import matplotlib.pyplot as plt\n",
                "from ipywidgets import interactive\n"
            ]
        },
        {
            "cell_type": "code",
            "execution_count": null,
            "metadata": {},
            "outputs": [],
            "source": [
                "# We define functions to compute the Taylor approximation of exp and sine\n",
                "# around zero for a given number of monomials to be used in the\n",
                "# approximation\n",
                "\n",
                "def expTaylor(x, d):\n",
                "    ans = np.zeros(x.shape)\n",
                "    for i in range(d):\n",
                "        ans += (x**i) * 1.0/np.math.factorial(i)\n",
                "    return ans\n",
                "\n",
                "def sineTaylor(x, d):\n",
                "    ans = np.zeros(x.shape)\n",
                "    for i in range(d):\n",
                "        if i % 2 == 1:\n",
                "            ans += (x**i) * ((-1.0)**((i-1)/2 % 2))/np.math.factorial(i)\n",
                "    return ans\n"
            ]
        },
        {
            "cell_type": "code",
            "execution_count": null,
            "metadata": {},
            "outputs": [],
            "source": [
                "# Utility function to show two functions on the same plot\n",
                "def plotTwoFuncs(x1Vals, y1Vals, x2Vals, y2Vals):\n",
                "    fig, ax = plt.subplots()\n",
                "    ax.plot(x1Vals, y1Vals, 'b-', x2Vals, y2Vals, 'g--')\n",
                "    ax.set(xlabel='x', ylabel='y',\n",
                "       title='Function approximation')\n",
                "    ax.legend(['Original', 'Approximation'],loc='upper right')\n",
                "    plt.show()\n"
            ]
        },
        {
            "cell_type": "code",
            "execution_count": null,
            "metadata": {},
            "outputs": [],
            "source": [
                "# define two functions to plot the functions exp and sine together with\n",
                "# their Taylor approximations\n",
                "def plotExpTaylorApprox(d):\n",
                "    xVals = np.linspace(-4,3,100)\n",
                "    expVals = np.exp(xVals)\n",
                "    plotTwoFuncs(xVals, expVals, xVals, expTaylor(xVals,d))\n",
                "def plotSineTaylorApprox(d):\n",
                "    xVals = np.linspace(-4,3,100)\n",
                "    sineVals = np.sin(xVals)\n",
                "    plotTwoFuncs(xVals, sineVals, xVals, sineTaylor(xVals, d))\n"
            ]
        },
        {
            "cell_type": "code",
            "execution_count": null,
            "metadata": {},
            "outputs": [],
            "source": [
                "# Play with the control shown below to visualize the effect of modifying\n",
                "# the number of terms used in the Taylor approximation\n",
                "interactive_plot = interactive(plotExpTaylorApprox, d=(1, 10))\n",
                "output = interactive_plot.children[-1]\n",
                "output.layout.height = '350px'\n",
                "interactive_plot\n"
            ]
        },
        {
            "cell_type": "code",
            "execution_count": null,
            "metadata": {},
            "outputs": [],
            "source": [
                "# Do the same for the sine approximation\n",
                "interactive_plot = interactive(plotSineTaylorApprox, d=(1, 10))\n",
                "output = interactive_plot.children[-1]\n",
                "output.layout.height = '350px'\n",
                "interactive_plot\n"
            ]
        },
        {
            "cell_type": "code",
            "execution_count": null,
            "metadata": {},
            "outputs": [],
            "source": [
                "# We define functions to approximate the function of part f using a Fourier\n",
                "# series\n",
                "def sgnFourier(x, d):\n",
                "    ans = np.zeros(x.shape)\n",
                "    for i in range(d):\n",
                "        if i % 2 == 1:\n",
                "            ans += np.sin(x*i) * 4.0/(i * np.pi)\n",
                "    return ans\n",
                "\n",
                "def plotSgnFourierApprox(d):\n",
                "    xVals = np.linspace(0,2*np.pi,100)\n",
                "    yVals = np.sign(np.pi - xVals)\n",
                "    plotTwoFuncs(xVals, yVals, xVals, sgnFourier(xVals,d))\n"
            ]
        },
        {
            "cell_type": "code",
            "execution_count": null,
            "metadata": {},
            "outputs": [],
            "source": [
                "# Adjust the control shown below to visualize the effect of changing\n",
                "# the number of terms used in the Fourier approximation\n",
                "interactive_plot = interactive(plotSgnFourierApprox, d=(1, 20))\n",
                "output = interactive_plot.children[-1]\n",
                "output.layout.height = '350px'\n",
                "interactive_plot\n"
            ]
        }
    ],
    "metadata": {
        "kernelspec": {
            "display_name": "Python 3",
            "language": "python",
            "name": "python3"
        },
        "language_info": {
            "codemirror_mode": {
                "name": "ipython",
                "version": 3
            },
            "file_extension": ".py",
            "mimetype": "text/x-python",
            "name": "python",
            "nbconvert_exporter": "python",
            "pygments_lexer": "ipython3",
            "version": "3.6.4"
        }
    },
    "nbformat": 4,
    "nbformat_minor": 4
}